/*
 * Copyright (C) 2021 ShangHai Quicktron Intelligent Technology Co.,Ltd
 * All Rights Reserved.
 * 本软件为上海快仓智能科技开发研制。未经本公司正式书面同意，其他任何个人、团体
 * 不得使用、复制、修改或发布本软件.
 * 版权所有 翻版必究
 */

package ATOPSTD;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
 * The type Able socket client.
 */
public class AbleSocketClient {
    /**
     * The Bw.
     */
    DataOutputStream bw;
    /**
     * The Br.
     */
    DataInputStream br;
    private Socket socket = null;
    private String sendValue = "\\0f\\00\\60\\00\\00\\00\\{commandNo}\\{lightNumber}{number}\\00";
    private String defaultNumber = "\\31\\32\\33\\34\\35\\36";
    private boolean bConnected = false;
    private String ip;
    private int port = 4660;

    /**
     * Instantiates a new Able socket client.
     *
     * @param ip the ip
     */
    public AbleSocketClient(String ip) {
        this.ip = ip;
    }

    /**
     * Instantiates a new Able socket client.
     *
     * @param ip   the ip
     * @param port the port
     */
    public AbleSocketClient(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    /**
     * Disconnect int.
     *
     * @return the int
     */
    public int disconnect() {
        int rs = 0;
        try {
            if (bw != null) {
                bw.close();
                bw = null;
            }
            if (socket != null) {
                socket.close();
                socket = null;
            }
            rs = 1;
        } catch (IOException e) {
            rs = -1;
        }
        return rs;
    }

    /**
     * Connect int.
     *
     * @return the int
     */
    public int connect() {
        int rs = 0;
        try {
            socket = new Socket(InetAddress.getByName(ip), port); // Server IP
            // and Port
            bw = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
            br = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
            bConnected = true;
            rs = 1;
        } catch (Exception e) {
            rs = -1;
        }
        return rs;
    }

    /**
     * Send command.
     *
     * @param commandNo   the command no
     * @param lightNumber the light number
     */
    public void sendCommand(int commandNo, int lightNumber) {
        sendCommand(commandNo, lightNumber, 0);
    }

    /**
     * Send command.
     *
     * @param commandNo   the command no
     * @param lightNumber the light number
     * @param value       the value
     */
    public void sendCommand(int commandNo, int lightNumber, Integer value) {
        String number = defaultNumber;
        if (value != null) {
            String valueStr = String.format("%06d", value);
            String[] valueStrs = valueStr.split("");
            StringBuilder sb = new StringBuilder("");
            for (String str : valueStrs) {
                if (str == null || "".equals(str.trim())) {
                    continue;
                }
                sb.append("\\3" + str);
            }
            number = sb.toString();
        }
        sendCommand(commandNo, lightNumber, number);
    }

    /**
     * Send command.
     *
     * @param commandNo   the command no
     * @param lightNumber the light number
     * @param value       the value
     */
    public void sendCommand(int commandNo, int lightNumber, String value) {
        String msg = sendValue.replace("{commandNo}", String.format("%02d", commandNo))
                              .replace("{lightNumber}", String.format("%02d", lightNumber)).replace("{number}", value);
        sendMsg(msg);
    }

    private void sendMsg(String msg) {
        byte[] ns = new byte[256];
        char[] tmpChar = new char[1];
        int i, len, idx;
        String tmpStr;
        len = msg.length();
        idx = 0;
        for (i = 0; i < len; i++) {
            tmpStr = msg.substring(i, i + 1);
            if (tmpStr.equals("\\")) {
                tmpStr = msg.substring(i + 1, i + 3);
                i = i + 2;
                ns[idx++] = (byte) Integer.parseInt(tmpStr, 16);
            } else {
                tmpChar = tmpStr.toCharArray();
                ns[idx++] = (byte) tmpChar[0];
            }
        }
        try {
            bw.write(ns, 0, idx);
            bw.flush();
        } catch (IOException e) {
        }
    }

    /**
     * Receive msg int.
     *
     * @param tagRcvMsg the tag rcv msg
     * @return the int
     */
    public int receiveMsg(TagRcvMsg tagRcvMsg) {
        int rs = 0;
        byte[] in_buf = new byte[15];
        StringBuffer hs;
        String stmp = "";
        if (bConnected) {
            try {
                br.read(in_buf, 0, 15);
                hs = new StringBuffer();
                for (int n = 0; n < in_buf.length; n++) {
                    stmp = (Integer.toHexString(in_buf[n] & 0XFF));
                    if (stmp.length() == 1) {
                        hs = hs.append(" ").append("0").append(stmp);
                    } else {
                        hs = hs.append(" ").append(stmp);
                    }
                }
                rs = 1;
                String[] strs = hs.toString().split(" ");
                tagRcvMsg.subcmd = Short.valueOf(strs[6]);
            } catch (IOException e) {
                rs = 1;
            }
        }
        return rs;
    }

    /**
     * Is server ok boolean.
     *
     * @return the boolean
     */
    public boolean isServerOk() {
        return socket != null && socket.isConnected();
    }

    /**
     * Gets ip.
     *
     * @return the ip
     */
    public String getIp() {
        return ip;
    }

    /**
     * Sets ip.
     *
     * @param ip the ip
     */
    public void setIp(String ip) {
        this.ip = ip;
    }

    /**
     * Gets port.
     *
     * @return the port
     */
    public int getPort() {
        return port;
    }

    /**
     * Sets port.
     *
     * @param port the port
     */
    public void setPort(int port) {
        this.port = port;
    }

    /**
     * The type Thread recv.
     */
    class ThreadRecv implements Runnable {
        /**
         * The In buf.
         */
        byte[] in_buf = new byte[15];
        /**
         * The Stmp.
         */
        String stmp;
        /**
         * The Hs.
         */
        StringBuffer hs;

        @Override
        public void run() {
            try {
                while (bConnected) {
                    br.read(in_buf, 0, 15);
                    hs = new StringBuffer();
                    stmp = "";
                    for (int n = 0; n < in_buf.length; n++) {
                        stmp = (Integer.toHexString(in_buf[n] & 0XFF));
                        if (stmp.length() == 1) {
                            hs = hs.append(" ").append("0").append(stmp);
                        } else {
                            hs = hs.append(" ").append(stmp);
                        }
                    }
                }
            } catch (Exception e) {
            } finally {
                if (br != null) {
                    try {
                        br.close();
                        br = null;
                    } catch (IOException e) {
                    }
                }
            }
        }

    }
}
